package com.fafian.gdc.core;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

import com.fafian.gdc.buttons.ButtonsController;
import com.fafian.gdc.socket.SocketController;
import com.fafian.publish.PublishBus;
import com.google.gson.Gson;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;

public class Runtime {

/*	private static class PrintOutListener implements Listener<Command>{
		
		private PrintOutListener(PublishBus bus){
			bus.registerListener(this, Command.class);
		}

		@Override
		public void notify(Command value) {
			switch(value){
			case PUSH_BUTTON1:
				System.out.println("Switching on relay1");
				break;
			case PUSH_BUTTON2:
				System.out.println("Switching on relay2");
				
			default:
				break;
		
			}
		}
		
	
	}
	*/
	
	private static Pin getPinFromId(int id){
		
		switch(id){
		case 0:
			return RaspiPin.GPIO_00;
		case 1:
			return RaspiPin.GPIO_01;
		case 2:
			return RaspiPin.GPIO_02;
		case 3:
			return RaspiPin.GPIO_03;
		case 4:
			return RaspiPin.GPIO_04;
		case 5:
			return RaspiPin.GPIO_05;
		case 6:
			return RaspiPin.GPIO_06;
		case 7:
			return RaspiPin.GPIO_07;
		case 8:
			return RaspiPin.GPIO_08;
		case 9:
			return RaspiPin.GPIO_09;
		case 10:
			return RaspiPin.GPIO_10;
		case 11:
			return RaspiPin.GPIO_11;
		case 12:
			return RaspiPin.GPIO_12;
		case 13:
			return RaspiPin.GPIO_13;
		case 14:
			return RaspiPin.GPIO_14;
		case 15:
			return RaspiPin.GPIO_15;
		case 16:
			return RaspiPin.GPIO_16;
		case 17:
			return RaspiPin.GPIO_17;
		case 18:
			return RaspiPin.GPIO_18;
		case 19:
			return RaspiPin.GPIO_19;
		case 20:
			return RaspiPin.GPIO_20;
		}
		return null;
		
	}
	
	
	private static class RelayPins{
		
		private GpioPinDigitalOutput relay1, relay2;
		
		public RelayPins(GpioPinDigitalOutput relay1, GpioPinDigitalOutput relay2){
			this.relay1 = relay1;
			this.relay2 = relay2;
			
		}

		/**
		 * @return the relay1
		 */
		public GpioPinDigitalOutput getRelay1() {
			return relay1;
		}

		/**
		 * @return the relay2
		 */
		public GpioPinDigitalOutput getRelay2() {
			return relay2;
		}		
		
	}
	
	public static RelayPins initGpio(GpioController gpio, Configuration config, ButtonsController bc){
		
		GpioPinDigitalInput button1 = gpio.provisionDigitalInputPin(getPinFromId(config.getButtonPin1()));
		GpioPinDigitalInput button2 = gpio.provisionDigitalInputPin(getPinFromId(config.getButtonPin2()));
		GpioPinDigitalOutput relay1 = gpio.provisionDigitalOutputPin(
				getPinFromId(config.getRelayPin1()),PinState.HIGH);
		GpioPinDigitalOutput relay2 = gpio.provisionDigitalOutputPin(
				getPinFromId(config.getRelayPin2()),PinState.HIGH);
		button1.addListener(bc);
		button2.addListener(bc);
		return new RelayPins(relay1, relay2);
	}
	
	public static Configuration readConfig(String fileName) throws IOException{
		String jsonConfig = new String(Files.readAllBytes(Paths
		        .get((new File(fileName)).toURI())));
		Gson gson = new Gson();
		return gson.fromJson(jsonConfig, Configuration.class);
	}
	
	
	public static void main(String[] args) {

		if (args.length != 1){
			System.out.println("Must provide config file name");
			System.out.println("Usage: gdc config_file_name");
			System.exit(-1);
		}
		
		Configuration config = null;
		
		try{
			config = readConfig(args[0]);
		}
		catch (Exception e){
			System.out.println("Error while reading config from file: "+args[0]);
			e.printStackTrace();
			System.exit(-1);
		}
		System.out.println("Starting gpio");
		
		final GpioController gpio = GpioFactory.getInstance();
		PublishBus bus = new PublishBus(false);
		SocketController sc= null;
		try {
			System.out.println("Init socket controller");
			final SocketController sc2 = new SocketController(bus, config.getSocketPort(), config.getApiKey());
			sc = sc2;
			System.out.println("Init buttons controller");
			ButtonsController bc = new ButtonsController(bus, config.getButtonPin1(), config.getButtonPin2());
			System.out.println("Init pins");
			RelayPins pins = initGpio(gpio, config, bc);
			System.out.println("Init gpio command listener");
			GpioCommandListener gcl = new GpioCommandListener(pins.getRelay1(), pins.getRelay2());
			gcl.register(bus);
			
			java.lang.Runtime.getRuntime().addShutdownHook((new Thread()
	        {
	            @Override
	            public void run()
	            {
	               sc2.stopController();
	               gpio.shutdown();
	            }
	        }));
			
			
			System.out.println("Starting socket controller");
			sc2.start();
			while(true) Thread.sleep(100);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally {
			System.out.println("Stopping socket controller");
			if (sc!=null)
				sc.stopController();
			System.out.println("Stopping gpio");
			gpio.shutdown();

		}
	}

}
